home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000 #2
/
Ham Radio 2000 - Volume 2.iso
/
HAMV2
/
TCP_IP
/
TNOS230S
/
AX25CMD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-14
|
43KB
|
1,791 lines
/* AX25 control commands
* Copyright 1991 Phil Karn, KA9Q
*
* Mods by G1EMM
* Mods by PA0GRI
* Mods by N1BEE
*/
/*
** FILE: ax25cmd.c
**
** AX.25 command handler.
**
** 09/24/90 Bob Applegate, wa2zzx
** Added BCTEXT, BC, and BCINTERVAL commands for broadcasting an id
** string using UI frames.
**
** 27/09/91 Mike Bilow, N1BEE
** Added Filter command for axheard control
*/
#include "global.h"
#ifdef AX25
#include "commands.h"
#include "mbuf.h"
#include "timer.h"
#include "proc.h"
#include "iface.h"
#include "mailbox.h"
#ifndef MSDOS
#include "session.h"
#endif
#include "nr4.h"
#include "pktdrvr.h"
#include "netrom.h"
#include "pool.h"
#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: ax25cmd.c,v 1.28 1997/09/14 14:37:46 root Exp root $";
#endif
static int doaxdest (int argc,char *argv[],void *p);
static int doaxfilter (int argc, char *argv[], void *p);
static int doaxflush (int argc, char *argv[], void *p);
static int doaxirtt (int argc, char *argv[], void *p);
static int doaxkick (int argc, char *argv[], void *p);
static int doaxreset (int argc, char *argv[], void *p);
static int doaxroute (int argc, char *argv[], void *p);
static int doaxwindow (int argc, char *argv[], void *p);
static int dobc (int argc, char *argv[], void *p);
static int dobcint (int argc, char *argv[], void *p);
static int dobcport (int argc, char *argv[], void *p);
static int dobctext (int argc, char *argv[], void *p);
static int doaxhport (int argc, char *argv[], void *p);
static int doaxhsize (int argc, char *argv[], void *p);
static int doblimit (int argc, char *argv[], void *p);
static int doaxuser (int argc, char *argv[], void *p);
static int dodigipeat (int argc, char *argv[], void *p);
static int domaxframe (int argc, char *argv[], void *p);
static int domycall (int argc, char *argv[], void *p);
static int don2 (int argc, char *argv[], void *p);
static int dopaclen (int argc, char *argv[], void *p);
static int dopthresh (int argc, char *argv[], void *p);
static int dot3 (int argc, char *argv[], void *p);
static int doaxtype (int argc, char *argv[], void *p);
static int dot4 (int argc, char *argv[], void *p);
static int doaxversion (int argc, char *argv[], void *p);
static int doaxmaxwait (int argc, char *argv[], void *p);
static int dosmartroute (int argc, char *argv[], void *p);
static int axdest (struct iface * ifp);
static int dorosecall (int argc, char *argv[], void *p);
static int docall (int argc, char *argv[], void *p, char call[]);
static int doax25paclen (int argc, char *argv[], void *p);
static int doax25timertype (int argc, char *argv[], void *p);
static int doax25irtt (int argc, char *argv[], void *p);
static int doax25version (int argc, char *argv[], void *p);
static int doax25t3 (int argc, char *argv[], void *p);
static int doax25t4 (int argc, char *argv[], void *p);
static int doax25n2 (int argc, char *argv[], void *p);
static int doax25maxframe (int argc, char *argv[], void *p);
static int doax25pthresh (int argc, char *argv[], void *p);
static int doax25window (int argc, char *argv[], void *p);
static int doax25blimit (int argc, char *argv[], void *p);
static int doax25maxwait (int argc, char *argv[], void *p);
static void dobroadtick (void);
static void displaycounters (struct iface *ifp, int addseparator);
#ifdef TUTOR
static int dotutorcall (int argc, char *argv[], void *p);
static int doinfocall (int argc, char *argv[], void *p);
static int donewscall (int argc, char *argv[], void *p);
#endif
#ifdef AXBCSTR
static void ax_bc (struct iface * axif, char *str);
#else
static void ax_bc (struct iface * axif);
#endif
#ifdef TTYCALL
static int dottycall (int argc, char *argv[], void *p);
extern char Ttycall[AXALEN]; /* the ttylink call in 'call' form */
#endif
extern int axheard_filter_flag; /* in axheard.c */
extern int lapbtimertype;
extern char Tcall[AXALEN];
extern char Icall[AXALEN];
extern char Ncall[AXALEN];
extern char Myalias[AXALEN];
extern char Nralias[ALEN + 1];
/* Defaults for IDing. */
static char *axbctext = NULLCHAR; /* Text to send */
static struct timer Broadtimer; /* timer for broadcasts */
char AXRosecall[AXALEN];
int AXSmartRoute = 0;
static long Axmaxwait = 0;
int Maxax25heard;
#ifdef POOLED
extern struct mempool lq_pool;
extern struct mempool ld_pool;
#endif
#ifdef CATALOG
#include "catalog.h"
#define CAT ax25cmd_catalog
#define smartroute __STR(0)
#define badalias __STR(1)
#define noiface __STR(2)
#define notax25 __STR(3)
#define bcaststr __STR(4)
#define bcasttimer __STR(5)
#define maxheard __STR(6)
#define alsonotax25 __STR(7)
#define notactive __STR(8)
#define heardheader __STR(9)
#define heardheader2 __STR(10)
#define destheader __STR(11)
#define heardfilter __STR(12)
#define filterusage __STR(13)
#define filtersrc __STR(14)
#define filterdest __STR(15)
#define stopstr __STR(16)
#define lumsstr __STR(17)
#define srttmdev __STR(18)
#define T1_4str __STR(19)
#define blimitstr __STR(20)
#define maxwaitstr __STR(21)
#define axversionstr __STR(22)
#define irttstr __STR(23)
#define polltimerstr __STR(24)
#define redundancystr __STR(25)
#define retrylimitstr __STR(26)
#define maxframestr __STR(27)
#define paclenstr __STR(28)
#define pthreshstr __STR(29)
#define windowstr __STR(30)
#define badcallsign __STR(31)
#define toomany __STR(32)
#define baddigi __STR(33)
#define addfailed __STR(34)
#define routeheader __STR(35)
#define routeusage __STR(36)
#define badtarget __STR(37)
#define notintable __STR(38)
#define timertypestr __STR(39)
#define timertypeusage __STR(40)
#define bctext_str __STR(41)
#else /* CATALOG */
static const char smartroute[] = "AX25 Smart Routing";
static const char badalias[] = "can't set alias\n";
static const char noiface[] = "you need to specify an interface\n";
static const char notax25[] = "not an AX.25 interface\n";
static const char bcaststr[] = "Broadcast text: %s\n";
static const char bcasttimer[] = "Broadcast timer %lu/%lu seconds\n";
static const char maxheard[] = "Max ax-heard";
static const char alsonotax25[] = "Interface %s not AX.25 type interface\n";
static const char notactive[] = "not active\n";
static const char heardheader[] = "Interface Station Time since send Pkts sent\n";
static const char heardheader2[] = "Station Time since heard Pkts rcvd : Station Time since heard Pkts rcvd\n";
static const char destheader[] = "Station Last ref Last heard Pkts\n";
static const char heardfilter[] = "ax25 heard filter";
static const char filterusage[] = "Usage: ax25 filter <0|1|2|3>\n";
static const char filtersrc[] = "Callsign logging by source %sabled, ";
static const char filterdest[] = "by destination %sabled\n";
static const char stopstr[] = "stop";
static const char lumsstr[] = "/%lu ms; ";
static const char srttmdev[] = "srtt = %lu mdev = %lu ";
static const char T1_4str[] = "T%c: ";
static const char blimitstr[] = "blimit";
static const char maxwaitstr[] = "retry maxwait";
static const char axversionstr[] = "AX25 version";
static const char irttstr[] = "Initial RTT (ms)";
static const char polltimerstr[] = "Idle poll timer (ms)";
static const char redundancystr[] = "Link redundancy timer (sec)";
static const char retrylimitstr[] = "Retry limit";
static const char maxframestr[] = "Window size (frames)";
static const char paclenstr[] = "Max frame length (bytes)";
static const char pthreshstr[] = "Poll threshold (bytes)";
static const char windowstr[] = "AX25 receive window (bytes)";
static const char badcallsign[] = "Bad callsign %s\n";
static const char toomany[] = "Too many digipeaters, or badly formed command.\n";
static const char baddigi[] = "Bad digipeater %s\n";
static const char addfailed[] = "Route add failed\n";
static const char routeheader[] = "Target Iface Type Mode Digipeaters\n";
static const char routeusage[] = "Usage: ax25 route add <target> <iface> [digis...]\n ax25 route drop <target> <iface>\n ax25 route mode <target> <iface> [mode]\n";
static const char badtarget[] = "Bad target %s\n";
static const char notintable[] = "Not in table\n";
static const char timertypestr[] = "AX25 timer type is ";
static const char timertypeusage[] = "use: ax25 timertype [original|linear|exponential]\n";
static const char bctext_str[] = "Bctext : %s\n";
#endif /* CATALOG */
static const char lustr[] = "%lu";
static const char unknownmode[] = "Unknown mode %s\n";
static const char unknowncmd[] = "Unknown command %s\n";
static const char originalstr[] = "original\n";
static const char linearstr[] = "linear\n";
static const char exponentialstr[] = "exponential\n";
static const char strCR[] = "%s\n";
static const char heardfmt[] = "%-9s %-9s %12s %7lu\n";
static const char str17[] = "%-17s";
static const char axstatheader[] =
#if defined(UNIX) || defined(TNOS_68K)
"&AXB Snd-Q Rcv-Q Remote Local Iface State\n";
#else
"&AXB Snd-Q Rcv-Q Remote Local Iface State\n";
#endif
static const char axstatfmt[] =
#if defined(UNIX) || defined(TNOS_68K)
"%8.8lx %-8d%-8d%-10s%-10s%-7s%s\n";
#else
"%4.4x %-8d%-8d%-10s%-10s%-7s%s\n";
#endif
static const char axcbheader[] =
#if defined(UNIX) || defined(TNOS_68K)
"&AXB Local Remote Iface RB V(S) V(R) Unack P Retry State\n";
#else
"&AXB Local Remote Iface RB V(S) V(R) Unack P Retry State\n";
#endif
static const char axcbfmt[] =
#if defined(UNIX) || defined(TNOS_68K)
"%8.8lx %-9s %-9s %-6s %c%c";
#else
"%4.4x %-9s %-9s %-6s %c%c";
#endif
const char *Ax25states[] =
{
"",
"Disconnected",
"Listening",
"Conn pending",
"Disc pending",
"Connected",
"Recovery",
};
/* Ascii explanations for the disconnect reasons listed in lapb.h under
* "reason" in ax25_cb
*/
const char *Axreasons[] =
{
"Normal",
"DM received",
"Timeout"
};
static struct cmds Axcmds[] =
{
{ "alias", donralias, 0, 0, NULLCHAR },
{ "bc", dobc, 0, 0, NULLCHAR },
{ "bcinterval", dobcint, 0, 0, NULLCHAR },
{ "bcport", dobcport, 0, 0, NULLCHAR },
{ "blimit", doblimit, 0, 0, NULLCHAR },
{ "bctext", dobctext, 0, 0, NULLCHAR },
{ "counters", doaxcounters, 0, 0, NULLCHAR },
{ "dest", doaxdest, 0, 0, NULLCHAR },
{ "digipeat", dodigipeat, 0, 0, NULLCHAR },
{ "filter", doaxfilter, 0, 0, NULLCHAR },
{ "flush", doaxflush, 0, 0, NULLCHAR },
{ "heard", doaxheard, 0, 0, NULLCHAR },
{ "hearddest", doaxdest, 0, 0, NULLCHAR },
{ "hport", doaxhport, 0, 0, NULLCHAR },
{ "hsize", doaxhsize, 0, 0, NULLCHAR },
#ifdef TUTOR
{ "infocall", doinfocall, 0, 0, NULLCHAR },
#endif
{ "irtt", doaxirtt, 0, 0, NULLCHAR },
{ "kick", doaxkick, 0, 2, "ax25 kick <axcb>" },
{ "maxframe", domaxframe, 0, 0, NULLCHAR },
{ "maxwait", doaxmaxwait, 0, 0, NULLCHAR },
{ "mycall", domycall, 0, 0, NULLCHAR },
#ifdef TUTOR
{ "newscall", donewscall, 0, 0, NULLCHAR },
#endif
{ "paclen", dopaclen, 0, 0, NULLCHAR },
{ "pthresh", dopthresh, 0, 0, NULLCHAR },
{ "reset", doaxreset, 0, 2, "ax25 reset <axcb>" },
{ "retries", don2, 0, 0, NULLCHAR },
{ "rosecall", dorosecall, 0, 0, NULLCHAR },
{ "route", doaxroute, 0, 0, NULLCHAR },
{ "smartroute", dosmartroute, 0, 0, NULLCHAR },
{ "status", doaxstat, 0, 0, NULLCHAR },
{ "t3", dot3, 0, 0, NULLCHAR },
{ "t4", dot4, 0, 0, NULLCHAR },
{ "timertype", doaxtype, 0, 0, NULLCHAR },
#ifdef TUTOR
{ "tutorcall", dotutorcall, 0, 0, NULLCHAR },
#endif
#ifdef TTYCALL
{ "ttycall", dottycall, 0, 0, NULLCHAR },
#endif
{ "user", doaxuser, 0, 0, NULLCHAR },
{ "version", doaxversion, 0, 0, NULLCHAR },
{ "window", doaxwindow, 0, 0, NULLCHAR },
{ NULLCHAR, NULL, 0, 0, NULLCHAR }
};
/* Multiplexer for top-level ax25 command */
int
doax25 (int argc, char *argv[], void *p)
{
return subcmd (Axcmds, argc, argv, p);
}
int
dosmartroute (int argc, char *argv[], void *p OPTIONAL)
{
return setbool (&AXSmartRoute, smartroute, argc, argv);
}
int
donralias (int argc, char *argv[], void *p OPTIONAL)
{
char tmp[AXBUF];
if (argc < 2) {
tprintf (strCR, pax25 (tmp, Myalias));
return 0;
}
if ((setcall (Myalias, argv[1]) == -1)
#ifdef NETROM
|| (putalias (Nralias, argv[1], 1) == -1)
#endif
) {
tputs (badalias);
Myalias[0] = '\0';
#ifdef NETROM
Nralias[0] = '\0';
#endif
return 0;
}
#ifdef MAILBOX
setmbnrid ();
#endif
return 0;
}
/*
** This function is called to send the current broadcast message
** and reset the timer.
*/
static int
dobc (int argc, char *argv[], void *p OPTIONAL)
{
struct iface *ifa;
if (argc < 2) {
tputs (noiface);
return 1;
}
if ((ifa = if_lookup (argv[1])) == NULLIF)
tprintf (Badinterface, argv[1]);
else if (ifa->type != CL_AX25)
tputs (notax25);
#ifdef AXBCSTR
else if (argc > 2)
ax_bc (ifa, argv[2]);
#endif
else {
#ifdef AXBCSTR
ax_bc (ifa, ifa->ax25->bctext);
#else
ax_bc (ifa);
#endif
start_detached_timer (&Broadtimer); /* stops if running and fire it up */
}
return 0;
}
/*
** View/Change the message we broadcast.
*/
static int
dobctext (int argc, char *argv[], void *p OPTIONAL)
{
struct iface *ifp;
if (argc < 2)
tprintf (bcaststr, axbctext);
else {
if (axbctext != NULL)
free (axbctext);
axbctext = strdup (argv[1]);
/* Set all ax.25 interfaces with no bc text */
for (ifp = Ifaces; ifp->next; ifp = ifp->next)
if (ifp->type == CL_AX25 && ifp->ax25->bctext == NULL)
ifp->ax25->bctext = strdup (axbctext);
}
return 0;
}
/*
** Examine/change the broadcast interval.
*/
static int
dobcint (int argc, char *argv[], void *p OPTIONAL)
{
if (argc < 2) {
tprintf (bcasttimer,
read_timer (&Broadtimer) / 1000L,
dur_timer (&Broadtimer) / 1000L);
return 0;
}
stop_timer (&Broadtimer); /* in case it's already running */
Broadtimer.func = (void (*)(void *)) dobroadtick; /* what to call on timeout */
Broadtimer.arg = NULLCHAR; /* dummy value */
set_timer (&Broadtimer, atoi (argv[1]) * 1000L); /* set timer duration */
start_detached_timer (&Broadtimer); /* and fire it up */
return 0;
}
/* Configure a port to do ax.25 beacon broadcasting */
static int
dobcport (int argc, char *argv[], void *p)
{
return (dosetflag (argc, argv, p, AX25_BEACON, 1));
}
/* Set the size of the ax.25 heard list */
int
doaxhsize (int argc, char *argv[], void *p)
{
if (argc > 1) /* if setting new size ... */
(void) doaxflush (argc, argv, p); /* we flush to avoid memory problems - K5JB */
return setint (&Maxax25heard, maxheard, argc, argv);
}
/* Configure a port to do ax.25 heard logging */
static int
doaxhport (int argc, char *argv[], void *p)
{
return (dosetflag (argc, argv, p, LOG_AXHEARD, 1));
}
static void
dobroadtick ()
{
struct iface *ifa;
ifa = Ifaces;
while (ifa != NULL) {
if (ifa->flags & AX25_BEACON)
#ifdef AXBCSTR
ax_bc (ifa, ifa->ax25->bctext);
#else
ax_bc (ifa);
#endif
ifa = ifa->next;
}
/* Restart timer */
start_detached_timer (&Broadtimer);
}
/*
** This is the low-level broadcast function.
*/
#ifdef AXBCSTR
static void
ax_bc (struct iface *axif, char *theaxbctext)
#else
static void
ax_bc (struct iface *axif)
#endif
{
struct mbuf *hbp;
int i;
#ifndef AXBCSTR
char *theaxbctext = axif->ax25->bctext;
#endif
/* prepare the header */
if ((theaxbctext == NULLCHAR) || (i = (int) strlen (theaxbctext)) == 0)
return;
if ((hbp = alloc_mbuf ((int16) i)) == NULLBUF)
return;
hbp->cnt = (int16) i;
memcpy (hbp->data, theaxbctext, (size_t) i);
(void) (*axif->output) (axif, Ax25multi[IDCALL], axif->hwaddr, PID_NO_L3, hbp); /* send it */
}
int
doaxheard (int argc, char *argv[], void *p OPTIONAL)
{
struct iface *ifp;
if (argc > 1) {
if ((ifp = if_lookup (argv[1])) == NULLIF) {
tprintf (Badinterface, argv[1]);
return 1;
}
if (ifp->output != ax_output) {
tprintf (alsonotax25, argv[1]);
return 1;
}
if (ifp->flags & LOG_AXHEARD)
(void) axheard (ifp);
else
tputs (notactive);
return 0;
}
for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
if (ifp->output != ax_output)
continue; /* Not an ax.25 interface */
if (axheard (ifp) == EOF)
break;
}
return 0;
}
int
axheard (struct iface *ifp)
{
int col = 0;
struct lq *lp;
char tmp[AXBUF];
if (ifp->hwaddr == NULLCHAR)
return 0;
tputs (heardheader);
tprintf (heardfmt, ifp->name, pax25 (tmp, ifp->hwaddr),
tformat (secclock () - ifp->lastsent), ifp->rawsndcnt);
tputs (heardheader2);
for (lp = Lq; lp != NULLLQ; lp = lp->next) {
if (lp->iface != ifp)
continue;
if (col)
tputs (" : ");
if (tprintf ("%-9s %12s %7lu", pax25 (tmp, lp->addr), tformat (secclock () - lp->time), lp->currxcnt) == EOF)
return EOF;
if (col) {
if (tputc ('\n') == EOF)
return EOF;
else
col = 0;
} else
col = 1;
}
if (col)
tputc ('\n');
return 0;
}
static int
doaxdest (int argc, char *argv[], void *p OPTIONAL)
{
struct iface *ifp;
if (argc > 1) {
if ((ifp = if_lookup (argv[1])) == NULLIF) {
tprintf (Badinterface, argv[1]);
return 1;
}
if (ifp->output != ax_output) {
tprintf (alsonotax25, argv[1]);
return 1;
}
(void) axdest (ifp);
return 0;
}
for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
if (ifp->output != ax_output)
continue; /* Not an ax.25 interface */
if (axdest (ifp) == EOF)
break;
}
return 0;
}
static int
axdest (struct iface *ifp)
{
struct ld *lp;
struct lq *lq;
char tmp[AXBUF];
if (ifp->hwaddr == NULLCHAR)
return 0;
tprintf ("%s:\n", ifp->name);
tputs (destheader);
for (lp = Ld; lp != NULLLD; lp = lp->next) {
if (lp->iface != ifp)
continue;
tprintf ("%-10s%-17s", pax25 (tmp, lp->addr), tformat (secclock () - lp->time));
if (addreq (lp->addr, ifp->hwaddr)) {
/* Special case; it's our address */
tprintf (str17, tformat (secclock () - ifp->lastsent));
} else if ((lq = al_lookup (ifp, lp->addr, 0)) == NULLLQ)
tprintf (str17, "");
else
tprintf (str17, tformat (secclock () - lq->time));
if (tprintf ("%8lu\n", lp->currxcnt) == EOF)
return EOF;
}
return 0;
}
static int
doaxfilter (int argc, char *argv[], void *p OPTIONAL)
{
if (argc >= 2)
(void) setint (&axheard_filter_flag, heardfilter, argc, argv);
else {
tputs (filterusage);
return 1;
}
tprintf (filtersrc, (axheard_filter_flag & AXHEARD_NOSRC) ? "dis" : "en");
tprintf (filterdest, (axheard_filter_flag & AXHEARD_NODST) ? "dis" : "en");
return 0;
}
static int
doaxflush (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
struct iface *ifp;
#ifndef POOLED
struct lq *lp, *lp1;
struct ld *ld, *ld1;
#endif
for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
if (ifp->output != ax_output)
continue; /* Not an ax.25 interface */
ifp->rawsndcnt = 0;
}
#ifdef POOLED
pool_free (&lq_pool);
#else
for (lp = Lq; lp != NULLLQ; lp = lp1) {
lp1 = lp->next;
free ((char *) lp);
}
#endif
Lq = NULLLQ;
#ifdef POOLED
pool_free (&ld_pool);
#else
for (ld = Ld; ld != NULLLD; ld = ld1) {
ld1 = ld->next;
free ((char *) ld);
}
#endif
Ld = NULLLD;
return 0;
}
static int
doaxreset (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
struct ax25_cb *axp;
axp = (struct ax25_cb *) htoi (argv[1]);
if (!ax25val (axp)) {
tputs (Notval);
return 1;
}
(void) reset_ax25 (axp);
return 0;
}
/* Display AX.25 link level control blocks */
int
doaxstat (int argc, char *argv[], void *p OPTIONAL)
{
register struct ax25_cb *axp;
char tmp[AXBUF];
char tmp2[AXBUF];
if (argc < 2) {
tputs (axstatheader);
for (axp = Ax25_cb; axp != NULLAX25; axp = axp->next) {
if (tprintf (axstatfmt, axp, len_q (axp->txq), len_p (axp->rxq),
pax25 (tmp, axp->remote), pax25 (tmp2, axp->local),
(axp->iface) ? axp->iface->name : "", Ax25states[axp->state]) == EOF)
return 0;
}
return 0;
}
axp = (struct ax25_cb *) htoi (argv[1]);
if (!ax25val (axp)) {
tputs (Notval);
return 1;
}
st_ax25 (axp);
return 0;
}
static void
displaycounters (struct iface *ifp, int addseparator)
{
struct ax25_counters *ac;
ac = &ifp->axcnt;
#if 0
if (addseparator)
tprintf ("---------------------------------------------------------------------\n");
tprintf ("\nAX25 Counters for Interface: %s\n\n", ifp->name);
tprintf ("Total Frames: %10ld in %10ld out\n Data Frames: %10ld in %10ld out\n",
ac->msgin, ac->msgout, ac->datain, ac->dataout);
tprintf (" Segments: %10ld in %10ld out %10ld errors\n RNRs: %10ld in %10ld out\n",
ac->segin, ac->segout, ac->segerr, ac->rnrin, ac->rnrout);
tprintf (" REJs: %10ld in %10ld out\n Retries: %10ld\n FRMR Recv: %10ld\n\n",
ac->rejin, ac->rejout, ac->retries, ac->frmerr);
#else
if (!addseparator)
tprintf ("\nAX25 Counters:\n\n"
" <-Frame Count-> <-Data Frames-> <-Segmented-> <--RNR--> <-REJ-> FRMR\n"
"name in out in out in out err in out in out Rtry in\n"
"------ ------- ------- ------- ------- ---- ---- --- ---- ---- --- --- ---- ---\n");
else if ((addseparator % 5) == 0)
tprintf ("-------------------------------------------------------------------------------\n");
tprintf ("%-7.7s%7ld %7ld %7ld %7ld %4ld %4ld %3ld %4ld %4ld %3ld %3ld %4ld %3ld\n",
ifp->name, ac->msgin, ac->msgout, ac->datain, ac->dataout, ac->segin,
ac->segout, ac->segerr, ac->rnrin, ac->rnrout, ac->rejin, ac->rejout,
ac->retries, ac->frmerr);
#endif
}
/* Display AX.25 link level counters */
int
doaxcounters (int argc, char *argv[], void *p OPTIONAL)
{
struct iface *ifp;
int count = 0;
int k;
if (argc < 2) {
for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
if (ifp->iftype->type == CL_AX25) {
displaycounters (ifp, count);
count++;
}
}
return 0;
}
for (k = 1; k < argc; k++) {
if ((ifp = if_lookup (argv[k])) == NULLIF) {
tprintf (Badinterface, argv[k]);
return 1;
}
displaycounters (ifp, count);
count++;
}
return 0;
}
/* Dump one control block */
void
st_ax25 (register struct ax25_cb *axp)
{
char tmp[AXBUF];
char tmp2[AXBUF];
int i;
char target[AXALEN];
if (axp == NULLAX25)
return;
tputs (axcbheader);
tprintf (axcbfmt, axp, pax25 (tmp, axp->local),
pax25 (tmp2, axp->remote), (axp->iface) ? axp->iface->name : "",
axp->flags.rejsent ? 'R' : ' ', axp->flags.remotebusy ? 'B' : ' ');
tprintf (" %4d %4d", axp->vs, axp->vr);
tprintf (" %02u/%02u %u", axp->unack, axp->maxframe, axp->proto);
tprintf (" %02u/%02u", axp->retries, axp->n2);
tprintf (" %s\n", Ax25states[axp->state]);
tprintf (srttmdev, axp->srt, axp->mdev);
tprintf (T1_4str, '1');
if (run_timer (&axp->t1))
tprintf (lustr, read_timer (&axp->t1));
else
tputs (stopstr);
tprintf (lumsstr, dur_timer (&axp->t1));
tprintf (T1_4str, '3');
if (run_timer (&axp->t3))
tprintf (lustr, read_timer (&axp->t3));
else
tputs (stopstr);
tprintf (lumsstr, dur_timer (&axp->t3));
tprintf (T1_4str, '4');
if (run_timer (&axp->t4))
tprintf (lustr, (read_timer (&axp->t4) / 1000L));
else
tputs (stopstr);
tprintf ("/%lu sec\n", (dur_timer (&axp->t4) / 1000L));
if (axp->route != NULLAXR) {
/* if the route is set, then it is a connection that
originated from here, and we know definitively this info */
tputs ("mode = ");
switch (axp->route->mode) {
case AX_VC_MODE: tputs ("VC");
break;
case AX_DATMODE: tputs ("DG");
break;
case AX_DEFMODE: tputs ("IF");
break;
default: tputs ("??");
break;
}
tputs (" Digipeaters =");
for (i = 0; i < axp->route->ndigis; i++) {
memcpy (target, axp->route->digis[i], AXALEN);
tprintf (" %s", pax25 (tmp, target));
}
tputc ('\n');
}
}
/* Set limit on retransmission backoff */
int
doax25blimit (int argc, char *argv[], void *p)
{
return setlong ((long *) p, blimitstr, argc, argv);
}
/* Set limit on retransmission backoff */
static int
doblimit (int argc, char *argv[], void *p OPTIONAL)
{
return doax25blimit (argc, argv, (void *) &Blimit);
}
/* Set limit on retransmission in ms */
int
doax25maxwait (int argc, char *argv[], void *p)
{
return setlong ((long *) p, maxwaitstr, argc, argv);
}
static int
doaxmaxwait (int argc, char *argv[], void *p OPTIONAL)
{
return doax25maxwait (argc, argv, (void *) &Axmaxwait);
}
/* Display or change our AX.25 address */
static int
domycall (int argc, char *argv[], void *p OPTIONAL)
{
char tmp[AXBUF];
if (argc < 2) {
tprintf (strCR, pax25 (tmp, Mycall));
return 0;
}
if (setcall (Mycall, argv[1]) == -1)
return -1;
#ifdef MAILBOX
setmbnrid ();
#endif
if (!memcmp (AXuser, NOCALL, AXALEN))
(void) setcall (AXuser, argv[1]);
return 0;
}
#ifdef TTYCALL
/* Display or change ttylink AX.25 address */
static int
dottycall (int argc, char *argv[], void *p OPTIONAL)
{
char tmp[AXBUF];
if (argc < 2) {
tprintf (strCR, pax25 (tmp, Ttycall));
return 0;
}
if (setcall (Ttycall, argv[1]) == -1)
return -1;
return 0;
}
#endif
static int
doaxuser (int argc, char *argv[], void *p OPTIONAL)
{
char tmp[AXBUF];
if (argc < 2) {
tprintf (strCR, pax25 (tmp, AXuser));
return 0;
}
if (setcall (AXuser, argv[1]) == -1)
return -1;
return 0;
}
/* Control AX.25 digipeating */
static int
dodigipeat (int argc, char *argv[], void *p)
{
return (dosetflag (argc, argv, p, AX25_DIGI, 1));
}
int
doax25version (int argc, char *argv[], void *p)
{
return setshort ((unsigned short *) p, axversionstr, argc, argv);
}
static int
doaxversion (int argc, char *argv[], void *p OPTIONAL)
{
return doax25version (argc, argv, (void *) &Axversion);
}
static int
doax25irtt (int argc, char *argv[], void *p)
{
return setlong ((long *) p, irttstr, argc, argv);
}
static int
doaxirtt (int argc, char *argv[], void *p OPTIONAL)
{
return doax25irtt (argc, argv, (void *) &Axirtt);
}
/* Set idle timer */
int
doax25t3 (int argc, char *argv[], void *p)
{
return setlong ((long *) p, polltimerstr, argc, argv);
}
/* Set idle timer */
static int
dot3 (int argc, char *argv[], void *p OPTIONAL)
{
return doax25t3 (argc, argv, &T3init);
}
/* Set link redundancy timer */
int
doax25t4 (int argc, char *argv[], void *p)
{
return setlong ((long *) p, redundancystr, argc, argv);
}
/* Set link redundancy timer */
static int
dot4 (int argc, char *argv[], void *p OPTIONAL)
{
return doax25t4 (argc, argv, (long *) &T4init);
}
/* Set retry limit count */
int
doax25n2 (int argc, char *argv[], void *p)
{
return setshort ((unsigned short *) p, retrylimitstr, argc, argv);
}
/* Set retry limit count */
static int
don2 (int argc, char *argv[], void *p OPTIONAL)
{
return doax25n2 (argc, argv, (void *) &N2);
}
/* Force a retransmission */
static int
doaxkick (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
struct ax25_cb *axp;
axp = (struct ax25_cb *) htoi (argv[1]);
if (!ax25val (axp)) {
tputs (Notval);
return 1;
}
(void) kick_ax25 (axp);
return 0;
}
/* Set maximum number of frames that will be allowed in flight */
int
doax25maxframe (int argc, char *argv[], void *p)
{
return setshort ((unsigned short *) p, maxframestr, argc, argv);
}
/* Set maximum number of frames that will be allowed in flight */
static int
domaxframe (int argc, char *argv[], void *p OPTIONAL)
{
return doax25maxframe (argc, argv, (void *) &Maxframe);
}
/* Set maximum length of I-frame data field */
int
doax25paclen (int argc, char *argv[], void *p)
{
return setshort ((unsigned short *) p, paclenstr, argc, argv);
}
/* Set maximum length of I-frame data field */
static int
dopaclen (int argc, char *argv[], void *p OPTIONAL)
{
return doax25paclen (argc, argv, (void *) &Paclen);
}
/* Set size of I-frame above which polls will be sent after a timeout */
int
doax25pthresh (int argc, char *argv[], void *p)
{
return setshort ((unsigned short *) p, pthreshstr, argc, argv);
}
/* Set size of I-frame above which polls will be sent after a timeout */
static int
dopthresh (int argc, char *argv[], void *p OPTIONAL)
{
return doax25pthresh (argc, argv, (void *) &Pthresh);
}
/* Set high water mark on receive queue that triggers RNR */
int
doax25window (int argc, char *argv[], void *p)
{
return setshort ((unsigned short *) p, windowstr, argc, argv);
}
/* Set high water mark on receive queue that triggers RNR */
static int
doaxwindow (int argc, char *argv[], void *p OPTIONAL)
{
return doax25window (argc, argv, (void *) &Axwindow);
}
/* End of ax25 subcommands */
#if defined(AX25) || defined(MAILBOX) || defined(AXUI)
/* Consolidate into one place the parsing of a connect path containing digipeaters.
* This is for gateway connects, by console connect cmd, by the
* axui command, and by the BBS forwarding process.
* We will place the derived path into the ax25 route table.
* Input: tokenized cmd line argc/argv: cmd iface target [via] digi1 [,] digi2 ... digiN
* interface *ifp.
* target, the node reached via digipeating.
* Output: ax25 route table is updated.
* Return code: 0 => error, else number of digis in path. -- K5JB
*/
int
connect_filt (int argc, char *argv[], char target[], struct iface *ifp, int mode)
{
int i, rtn_argc, ndigis, dreg_flag = 0;
char digis[MAXDIGIS][AXALEN];
char *nargv[MAXDIGIS + 1];
char *cp, *dreg = NULLCHAR;
ndigis = argc - 3; /* worst case */
for (i = 0, rtn_argc = 0; i < ndigis && rtn_argc < MAXDIGIS + 1; i++) {
cp = argv[i + 3];
get_dreg:
switch (*cp) {
case ',':
if (!*(cp + 1)) /* lone comma */
continue; /* skip it */
else { /* leading comma, a faux pas */
nargv[rtn_argc++] = ++cp;
if (*cp == ',') { /* sequential commas are illegal */
rtn_argc = MAXDIGIS + 1; /* force for() loop exit */
continue;
}
break;
}
case 'v':
if (!strncmp ("via", cp, strlen (cp))) /* should get 'em all */
continue; /* skip it */
default:
nargv[rtn_argc++] = cp;
break;
}
for (; *cp; cp++) /* remove any trailing commas */
if (*cp == ',') {
*cp = '\0';
if (*(cp + 1) != '\0') { /* something dangling */
dreg = cp + 1; /* restart scan here */
dreg_flag = 1;
}
break;
}
if (dreg_flag) {
dreg_flag = 0;
cp = dreg; /* go back and get the dreg */
goto get_dreg;
}
}
if (rtn_argc > MAXDIGIS || ndigis < 1) {
tputs (toomany);
return 0;
}
for (i = 0; i < rtn_argc; i++) {
if (setcall (digis[i], nargv[i]) == -1) { /*lint !e771 */
tprintf (baddigi, nargv[i]);
return 0;
}
}
if (ax_add (target, mode, digis, rtn_argc, ifp) == NULLAXR) {
tputs (addfailed);
return 0;
}
return (rtn_argc);
}
#endif
/* Initiate interactive AX.25 connect to remote station */
int
doconnect (int argc, char *argv[], void *p OPTIONAL)
{
struct sockaddr_ax fsocket;
struct session *sp;
struct iface *ifp;
char target[AXALEN];
int split = 0;
char tmp[AXBUF];
/*Make sure this comes from console - WG7J*/
if (Curproc->input != Command->input)
return 0;
#ifdef ALLSERV
if (argv[0][0] == 's') /* use split screen */
split = 1;
#endif
if (((ifp = if_lookup (argv[1])) != NULLIF) && (ifp->type != CL_AX25)) {
tprintf (alsonotax25, argv[1]);
return 1;
}
if (ifp == NULLIF) {
tprintf (Badinterface, argv[1]);
#if defined(MAILBOX) && defined(GATECMDS)
(void) dombports (0, NULL, NULL);
#endif
return 1;
}
if (argc > 3 && !strcmp (argv[3], "@")) {
free (argv[3]);
argv[3] = strdup (pax25 (tmp, AXRosecall));
}
if (setcall (target, argv[2]) == -1) {
tprintf (badcallsign, argv[2]);
return 1;
}
/* If digipeaters are given, put them in the routing table */
if (argc > 3) {
if (connect_filt (argc, argv, target, ifp, AX_SETUP) == 0)
return 1;
}
/* Allocate a session descriptor */
if ((sp = newsession (argv[2], AX25TNC, split)) == NULLSESSION) {
tputs (TooManySessions);
return 1;
}
if ((sp->s = socket (AF_AX25, SOCK_STREAM, 0)) == -1) {
tputs (Nosock);
freesession (sp);
(void) keywait (NULLCHAR, 1);
return 1;
}
fsocket.sax_family = AF_AX25;
memcpy (fsocket.ax25_addr, AXuser, AXALEN);
(void) bind (sp->s, (char *) &fsocket, sizeof (struct sockaddr_ax));
(void) setcall (fsocket.ax25_addr, argv[2]);
strncpy (fsocket.iface, argv[1], ILEN - 1);
return tel_connect (sp, (char *) &fsocket, sizeof (struct sockaddr_ax));
}
/* Display and modify AX.25 routing table */
static int
doaxroute (int argc, char *argv[], void *p OPTIONAL)
{
char tmp[AXBUF];
int i, ndigis;
register struct ax_route *axr;
struct ax_route **routetbl = &Ax_setups;
char target[AXALEN], digis[MAXDIGIS][AXALEN];
struct iface *iface;
const char *typestr;
if (argc < 2) {
tputs (routeheader);
do {
for (axr = *routetbl; axr != NULLAXR; axr = axr->next) {
memcpy (target, axr->target, AXALEN);
target[AXALEN - 1] |= (AXN | Q);
switch (axr->type) {
case AX_LOCAL: typestr = "Local";
break;
case AX_SETUP: typestr = "Setup";
break;
default: typestr = "Auto";
}
tprintf ("%-10s%-7s%-6s", pax25 (tmp, target),
axr->iface->name, typestr);
switch (axr->mode) {
case AX_VC_MODE: tputs (" VC ");
break;
case AX_DATMODE: tputs (" DG ");
break;
case AX_DEFMODE: tputs (" IF ");
break;
default: tputs (" ?? ");
break;
}
for (i = 0; i < axr->ndigis; i++) {
memcpy (target, axr->digis[i], AXALEN);
#if 0 /* shouldn't be needed */
target[AXALEN - 1] |= (AXN | Q);
#endif
tprintf (" %s", pax25 (tmp, target));
}
if (tputc ('\n') == EOF)
return 0;
}
if (routetbl == &Ax_setups)
routetbl = &Ax_routes;
else
routetbl = (struct ax_route **)0;
} while (routetbl != (struct ax_route **)0);
return 0;
}
if (argc < 4) {
tputs (routeusage);
return 1;
}
if (setcall (target, argv[2]) == -1) {
tprintf (badtarget, argv[2]);
return 1;
}
if ((iface = if_lookup (argv[3])) == NULLIF) {
tprintf (Badinterface, argv[3]);
return 1;
}
switch (argv[1][0]) {
case 'a': /* Add route */
ndigis = argc - 4;
if (ndigis > MAXDIGIS) {
tputs (toomany);
return 1;
}
for (i = 0; i < ndigis; i++) {
if (setcall (digis[i], argv[i + 4]) == -1) {
tprintf (baddigi, argv[i + 4]);
return 1;
}
}
if (ax_add (target, AX_LOCAL, digis, ndigis, iface) == NULLAXR) {
tputs (addfailed);
return 1;
}
break;
case 'd': /* Drop route */
if (ax_drop (target, iface, AX_NONSETUP) == -1) {
tputs (notintable);
return 1;
}
break;
case 'm': /* Alter route mode */
if (argc < 5) {
tputs (routeusage);
return 1;
}
if ((axr = ax_lookup (NULLCHAR, target, iface, AX_NONSETUP)) == NULLAXR) {
tputs (notintable);
return 1;
}
switch (argv[4][0]) {
case 'i': /* use default interface mode */
axr->mode = AX_DEFMODE;
break;
case 'v': /* use virtual circuit mode */
axr->mode = AX_VC_MODE;
break;
case 'd': /* use datagram mode */
axr->mode = AX_DATMODE;
break;
default:
tprintf (unknownmode, argv[4]);
return 1;
}
break;
default:
tprintf (unknowncmd, argv[1]);
return 1;
}
return 0;
}
/* ax25 timers type - linear v exponential */
int
doax25timertype (int argc, char *argv[], void *p)
{
if (argc < 2) {
tputs (timertypestr);
switch (*(int *) p) {
case 2:
tputs (originalstr);
break;
case 1:
tputs (linearstr);
break;
case 0:
tputs (exponentialstr);
break;
default:
break;
}
return 0;
}
switch (argv[1][0]) {
case 'o':
case 'O': *(int *) p = 2;
break;
case 'l':
case 'L': *(int *) p = 1;
break;
case 'e':
case 'E': *(int *) p = 0;
break;
default: tputs (timertypeusage);
return -1;
}
return 0;
}
/* ax25 timers type - linear v exponential */
static int
doaxtype (int argc, char *argv[], void *p OPTIONAL)
{
return doax25timertype (argc, argv, (void *) &lapbtimertype);
}
/* Display or change an AX.25 tutorial-type call */
static int
docall (int argc, char *argv[], void *p OPTIONAL, char call[])
{
char tmp[AXBUF];
if (argc < 2) {
tprintf (strCR, pax25 (tmp, call));
return 0;
}
if (setcall (call, argv[1]) == -1)
return -1;
return 0;
}
/* Display or change our AX.25 rose entry call */
static int
dorosecall (int argc, char *argv[], void *p)
{
return (docall (argc, argv, p, AXRosecall));
}
#ifdef TUTOR
/* Display or change our AX.25 tutorial call */
static int
dotutorcall (int argc, char *argv[], void *p)
{
return (docall (argc, argv, p, Tcall));
}
/* Display or change our AX.25 info call */
static int
doinfocall (int argc, char *argv[], void *p)
{
return (docall (argc, argv, p, Icall));
}
/* Display or change our AX.25 news call */
static int
donewscall (int argc, char *argv[], void *p)
{
return (docall (argc, argv, p, Ncall));
}
#endif
void
init_ifax25 (struct ifax25 *ax25)
{
if (!ax25)
return;
/* Set interface to the defaults */
ax25->paclen = Paclen;
ax25->lapbtimertype = lapbtimertype;
ax25->irtt = Axirtt;
ax25->version = Axversion;
ax25->t3 = T3init;
ax25->t4 = T4init;
ax25->n2 = N2;
ax25->maxframe = Maxframe;
ax25->pthresh = Pthresh;
ax25->window = Axwindow;
ax25->blimit = Blimit;
ax25->maxwait = Axmaxwait;
if (axbctext)
ax25->bctext = strdup (axbctext);
}
static int doifax25paclen (int argc, char *argv[], void *p);
static int doifax25timertype (int argc, char *argv[], void *p);
static int doifax25irtt (int argc, char *argv[], void *p);
static int doifax25version (int argc, char *argv[], void *p);
static int doifax25t3 (int argc, char *argv[], void *p);
static int doifax25t4 (int argc, char *argv[], void *p);
static int doifax25n2 (int argc, char *argv[], void *p);
static int doifax25maxframe (int argc, char *argv[], void *p);
static int doifax25pthresh (int argc, char *argv[], void *p);
static int doifax25window (int argc, char *argv[], void *p);
static int doifax25blimit (int argc, char *argv[], void *p);
static int doifax25maxwait (int argc, char *argv[], void *p);
static int doifax25bctext (int argc, char *argv[], void *p);
/* These are the command that set ax.25 parameters per interface */
static struct cmds Ifaxcmds[] =
{
{ "bctext", doifax25bctext, 0, 0, NULLCHAR },
{ "blimit", doifax25blimit, 0, 0, NULLCHAR },
{ "irtt", doifax25irtt, 0, 0, NULLCHAR },
{ "maxframe", doifax25maxframe, 0, 0, NULLCHAR },
{ "maxwait", doifax25maxwait, 0, 0, NULLCHAR },
{ "paclen", doifax25paclen, 0, 0, NULLCHAR },
{ "pthresh", doifax25pthresh, 0, 0, NULLCHAR },
{ "retries", doifax25n2, 0, 0, NULLCHAR },
{ "timertype", doifax25timertype, 0, 0, NULLCHAR },
{ "t3", doifax25t3, 0, 0, NULLCHAR },
{ "t4", doifax25t4, 0, 0, NULLCHAR },
{ "version", doifax25version, 0, 0, NULLCHAR },
{ "window", doifax25window, 0, 0, NULLCHAR },
{ NULLCHAR, NULL, 0, 0, NULLCHAR }
};
int
ifax25 (int argc, char *argv[], void *p)
{
if (((struct iface *) p)->type != CL_AX25)
return tputs (notax25);
return subcmd (Ifaxcmds, argc, argv, p);
}
/* Set ax.25 bctext */
static int
doifax25bctext (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
if (argc == 1)
tprintf (bctext_str, ifp->ax25->bctext);
else {
if (ifp->ax25->bctext)
free (ifp->ax25->bctext);
if (strlen (argv[1]) == 0) /* clearing the buffer */
ifp->ax25->bctext = NULL;
else
ifp->ax25->bctext = strdup (argv[1]);
}
return 0;
}
static int
doifax25blimit (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
return doax25blimit (argc, argv, (void *) &ifp->ax25->blimit);
}
static int
doifax25irtt (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
return doax25irtt (argc, argv, (void *) &ifp->ax25->irtt);
}
static int
doifax25maxframe (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
return doax25maxframe (argc, argv, (void *) &ifp->ax25->maxframe);
}
static int
doifax25maxwait (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
return doax25maxwait (argc, argv, (void *) &ifp->ax25->maxwait);
}
/* Set interface AX.25 Paclen, and adjust the NETROM mtu for the
* smallest paclen. - WG7J
*/
static int
doifax25paclen (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
#ifdef NETROM
int tmp;
#endif
(void) doax25paclen (argc, argv, (void *) &ifp->ax25->paclen);
#ifdef NETROM
if (argc > 1 && ifp->flags & IS_NR_IFACE) {
if ((tmp = ifp->ax25->paclen - 20) < Nr_iface->mtu)
Nr_iface->mtu = (int16) tmp;
}
#endif
return 0;
}
static int
doifax25pthresh (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
return doax25pthresh (argc, argv, (void *) &ifp->ax25->pthresh);
}
static int
doifax25n2 (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
return doax25n2 (argc, argv, (void *) &ifp->ax25->n2);
}
static int
doifax25timertype (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
return doax25timertype (argc, argv, (void *) &ifp->ax25->lapbtimertype);
}
static int
doifax25t3 (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
return doax25t3 (argc, argv, (void *) &ifp->ax25->t3);
}
static int
doifax25t4 (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
return doax25t4 (argc, argv, (void *) &ifp->ax25->t4);
}
static int
doifax25version (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
return doax25version (argc, argv, (void *) &ifp->ax25->version);
}
static int
doifax25window (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
return doax25window (argc, argv, (void *) &ifp->ax25->window);
}
#endif /* AX25 */